/**
* Abstract: Task Manager Device
*
* Version: 1.0
*
* Disclaimer: IMPORTANT:  This Gamenova software is supplied to you by
* 4E Studios Srl("4E") in consideration of your agreement to the following terms,
* and your use, installation, modification or redistribution of this 4E software
* constitutes acceptance of these terms.  If you do not agree with these terms,
* please do not use, install, modify or redistribute this 4E software.
*
* In consideration of your agreement to abide by the following terms, and subject
* to these terms, 4E grants you a personal, non-exclusive license, under
* 4E's copyrights in this original 4E software (the "4E Software"), to
* use, reproduce, modify and redistribute the 4E Software, with or without
* modifications, in source and/or binary forms; provided that if you redistribute
* the 4E Software in its entirety and without modifications, you must retain
* this notice and the following text and disclaimers in all such redistributions
* of the 4E Software.
* Neither the name, trademarks, service marks or logos of 4E Studios Srl may be used
* to endorse or promote products derived from the 4E Software without specific
* prior written permission from 4E.  Except as expressly stated in this notice,
* no other rights or licenses, express or implied, are granted by 4E herein,
* including but not limited to any patent rights that may be infringed by your
* derivative works or by other works in which the 4E Software may be
* incorporated.
*
* The 4E Software is provided by 4E on an "AS IS" basis.  4E MAKES NO
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, REGARDING THE 4E SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
* COMBINATION WITH YOUR PRODUCTS.
*
* IN NO EVENT SHALL 4E BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
* DISTRIBUTION OF THE 4E SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
* CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
* 4E HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (C) 2011 4E Studios Srl All Rights Reserved.
*/


// Gamenova Tasks Library

      /**

         Task class
         @constructor
      */
      function Task(name)
      {
        this.name = name || "";
        this.accumTime = 0;
        this.updateInterval = 16;
        this.code = null;
      }

      /**
        Task Manager Device CLass
        @constructor
      */
      function GNCore()
      {
  
     /**
            Checks if a file has been imported 
        */
        this.requires = function(filepath){

            var scripts = document.getElementsByTagName("script");

            var baseLocation = window.location.href;

            baseLocation = baseLocation.substring(0,baseLocation.lastIndexOf("/")+1);

            filepath = baseLocation + filepath;

            for(var i=0; i<scripts.length; i++){

                var script = scripts[i];



                if(script.src === filepath)
                    return true;
            }

            throw new Error("No such file: " + filepath);
        }

        this.inclusions = [];

        this.include_ = function(filepath){

          this.inclusions.push(filepath);
        };

        /**
            Imports a new file 
        */
        this.include = function(filepath){



             var scripts = document.getElementsByTagName("script");

            var baseLocation = window.location.href;

            baseLocation = baseLocation.substring(0,baseLocation.lastIndexOf("/")+1);

            filepath = baseLocation + filepath;

            for(var i=0; i<scripts.length; i++){

                var script = scripts[i];

                if(script.src === filepath)
                    return true;
            }


            // includes it
            var script = document.createElement("script");
            script.src = filepath;
            document.head.appendChild(script);
            

        }

        /**
          Default number of fps used by the Tasks
        */
        this.FPS = 60;

        var curDate = new Date();

        /**
          Beginning time
        */
        this.startTimeSince1970 = Date.now();

        /**
          Actual time
        */
        this.curTime = this.startTimeSince1970;

        /**
            Actual time in msec
        */
        this.time = 0;

        /**
          Last detected time in msec
        */
        this.lastTime = 0;

        /**
          Elapsed time from the previous frame
        */
        this.dt = 0;

        this.list = new Object();
        this.array = [];

    
        /**

            GNCore setup function reference
        */
        this.gnSetup = function(){};

        /**
            GN Setup function
        */
        this.onSetup = function(fun){

            this.gnSetup = fun;

        };


        /**
            Schedules a new task
            @this
            @param {string} name  Name of the task.
            @param {number} interval  Interval in msec for task scheduling.
            @param {object} code  Function of the code of the task.
        */
        this.newTask = function(name, interval, code) {
          this.list[name] = new Task(name);
          this.list[name].updateInterval = interval;
          this.list[name].code = code;
        };

        var EMPTY_FUNCTION = function(){};

        /**
            Sets the frame rate of the mian loop
            @function
            @param {number} fps Number of the desired frames per second
        */
        this.setFPS = function(fps){

          this.FPS = fps;
        }
        

        /**
            Stops the Task Manager.
            @function
        */
        this.exit = function()
        {
            this.pause();

            this.onExit();

            this.releaseTasks();

          
        };

        /**
           Window id
           @inner
        */
        this.wndId = 0;

        /**
          Updates the current tasks.
          @this
        */
        this.run = function() {

           if (document.readyState == 'complete') {

           
              
                // calls the setup function
                this.gnSetup(); 

                GNCore._updTasks();
          }
          else
          {
            setTimeout(function(){ GNCore.run(); },1000);
          }

        };

        

        /**
            Deschedules all the tasks removing them from memory.
            @this
        */
        this.releaseTasks = function() {
            // aggiorna i tasks
            var task = null;
            for (var k in GNCore.list)
            {
               delete GNCore.list[k];

            }
        }

        /**
          Removes a task from the Tasks
          @this
          @param {string} taskname  Name of the task to remove.
        */
        this.destroy = function(taskname) {
          delete this.list[taskname];
        }; 

        /**
          Profiling time in msec
        */
        this.lastExecTime = 16;

        // Overrides default requestAnimFrame
        window.requestAnimFrame = (function(){
          return  window.requestAnimationFrame       || 
                  window.webkitRequestAnimationFrame || 
                  window.mozRequestAnimationFrame    || 
                  window.oRequestAnimationFrame      || 
                  window.msRequestAnimationFrame     || 
                  function( callback ){
                    //console.log("setTimeout");
                    window.setTimeout(callback, 1000 / 60);
                  };
        })();

        /**
        Cancel requestAnimationFrame in a cross browser way.
      */
      window.cancelRequestAnimFrame = (function() {
            return window.cancelAnimationFrame ||
                window.webkitCancelRequestAnimationFrame ||
                window.mozCancelRequestAnimationFrame ||
                window.oCancelRequestAnimationFrame ||
                window.msCancelRequestAnimationFrame ||
                clearTimeout;
        })();

        // animframeCallbackId
        this.requestanimframeCallbackId=0;

        /**
          Updates the current tasks.
          @this
        */
        this._updTasks = function() {

            GNCore.requestanimframeCallbackId = window.requestAnimFrame(GNCore._updTasks);

            GNCore.lastTime = Date.now();

            var elapsed = (GNCore.lastTime - GNCore.curTime);

            GNCore.dt = elapsed > 1000 ? 1000 : elapsed;

            GNCore.curTime = GNCore.lastTime;

            GNCore.time = GNCore.curTime - GNCore.startTimeSince1970;

            var time = Date.now();

            GNCore.runTasks(GNCore.dt);

            var now = Date.now();

            GNCore.lastExecTime = now - time;

        }

        /**
            Executes all the tesks in the qeue
            @this
            @param {number} dt    Elapsed time from the last frame.
        */
        this.runTasks = function(dt) {
           // aggiorna i tasks
            var task = null;
            for (var k in GNCore.list)
            {
               task = GNCore.list[k];

              task.accumTime += dt;

              if (task.accumTime >= task.updateInterval)
              {
                task.code(task.accumTime);

                task.accumTime = 0;
              }

            }
        }

        /**
          Stores the old update task function
        */
        this._oldUpdateTasks = EMPTY_FUNCTION;

        /**
          Is the task manager pasued, or running?
        */
        this.paused = false;

        /**
            Mette in pausa i tasks
            @this
        */
        this.pause = function() {
           if (this.paused == false)
            {

              window.cancelRequestAnimFrame(this.requestanimframeCallbackId);
              this._oldUpdateTasks = this._updTasks;

              this._updTasks = EMPTY_FUNCTION;

              this.paused = true;
            }
        }

        /**
          Resumes task execution after a pause
          @this
        */
        this.resume = function() {
            if (this.paused == true)
            {
              this._updTasks = this._oldUpdateTasks;
              
              this.paused = false;

              this._updTasks();
            }
        }


        /**
          Step one frame in the task execution
          @this
          @param {number} dt    Elapsed time from the last frame.
        */
        this.step = function(dt) {
          if (dt === undefined)
            dt = 16;

          if (this.paused == true)
          {
            this.runTasks(dt);
            
          }
        }

      }

      window.GNCore = new GNCore();

